/* 
 * Config.java      1.00    2008-01-11
 *
 * Copyright (c) 2010 jung. All Rights Reserved.
 * 
 * This software is the confidential and proprietary information
 * of jung.  You shall not disclose such Confidential Information
 * and shall use it only in accordance with the terms of the license agreement
 * you entered into with jung.
 */
package doit.framework.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Vector;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jdom.Attribute;
import org.jdom.Comment;
import org.jdom.DataConversionException;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

/**
 * <pre>
 * system      : 공통
 * menu        : 공통
 * source      : Config.java
 * description : config.xml 관리
 * </pre> 
 * @version
 * <pre> 
 * 1.0  2008-01-11  jung  최초 작성
 * 1.1  
 * </pre>
 */

public class Config {
    
    private static Log logger = LogFactory.getLog(Config.class);
	
	private final String CONFIG_NAME = "config";
	
	private final String CONFIG_EXT = "xml";
	
	private final String CONFIG_FILE_NAME = CONFIG_NAME + "." + CONFIG_EXT;
	
	private final String DEFAULT_PATH = "Learning";

	private final String VERSION_NAME = "version";

	private final String VERSION = "1.0";

	private URL xmlURL = null;

	private Document xmlDoc = null;

	private SAXBuilder sax = null;

	private XMLOutputter xmlOut = null;

	private String configFile = CONFIG_FILE_NAME;
	
	/**
	 * 갱신 시간
	 */
	private long lastModified = 0;

	// Singleton
	private static Config instance = null;

	public static Config getInstance() {
		if (instance == null) {
			instance = new Config();
		}
		return instance;
	}
	
	public static void init() {
	    if (instance == null) {
            instance = new Config();
        }
	}
	
	/**
	 * 초기화
	 */
	private Config() {
		String myIp = null;
		try {
			InetAddress myHost = InetAddress.getLocalHost();
			myIp = myHost.getHostAddress();
		} catch( UnknownHostException e) {
		}

		// ip 기준으로 있는지 조회한다.
		URL url = this.getClass().getClassLoader().getResource( CONFIG_NAME + "." + myIp + "." + CONFIG_EXT);
		
		// 없으면 config.xml을 조회한다.
		if( url == null)
			url = this.getClass().getClassLoader().getResource( configFile);
		else
			configFile = CONFIG_NAME + "." + myIp + "." + CONFIG_EXT;
		
		if (url == null) {
			if (Constants.DEBUG_MODE) {
				logger.error("'" + configFile + "' 파일을 Classpath내에서 찾을 수 없습니다.");
				System.exit(0);
			}
		}

		xmlURL = url;

		Format xmlFormat = Format.getPrettyFormat();
		xmlFormat.setEncoding("UTF-8");
		xmlFormat.setIndent("\t");

		sax = new SAXBuilder();
		xmlOut = new XMLOutputter(xmlFormat);
		
		_read();
		
		instance = this;
		
		logger.info("Load XML : " + CONFIG_FILE_NAME);
	}

	/**
	 * 설정항목이 존재하는지 검사
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @return 존재할 경우 true, 존재하지 않을 경우 false
	 *
	 */
	private boolean _contains(String tagName) {
		boolean ret = false;

		if (_getElement(tagName, null) != null) {
			ret = true;
		}

		return ret;
	}

	/**
	 * 설정항목의 속성이 존재하는지 검사
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @param attrName
	 *            속성 이름
	 * @return 존재할 경우 true, 존재하지 않을 경우 false
	 *
	 */
	private boolean _contains(String tagName, String attrName) {
		boolean ret = false;

		if (_getAttribute(tagName, attrName) != null) {
			ret = true;
		}

		return ret;
	}

	/**
	 * 설정항목을 생성한다.
	 *
	 * @param tagName
	 *            생성할 설정항목 이름
	 * @param value
	 *            입력할 문자열값
	 * @return 설정항목 생성에 성공하면 true, 실패하면 false
	 */
	private boolean _make(String tagName, String value) {
		boolean ret = false;

		if (!_contains(tagName)) {
			Element e = _makeElement(tagName, null);
			if (e != null) {
				e.setText(value);
				ret = true;
			}
			if (ret) {
				_write();
			}
		}

		return ret;
	}

	/**
	 * 설정항목을 생성한다.
	 *
	 * @param tagName
	 *            생성할 설정항목 이름
	 * @param value
	 *            입력할 int값
	 * @return 설정항목 생성에 성공하면 true, 실패하면 false
	 */
	private boolean _make(String tagName, int value) {
		return _make(tagName, "" + value);
	}

	/**
	 * 설정항목을 생성한다.
	 *
	 * 리스트에 들어 있는 내용은 모두 String으로 처리한다.
	 *
	 * @param tagName
	 *            생성할 설정항목 이름
	 * @param value
	 *            입력할 리스트
	 * @return 설정항목 생성에 성공하면 true, 실패하면 false
	 */
	private boolean _make(String tagName, List valueList) {
		boolean ret = false;

		if (tagName == null || valueList == null) {
			return ret;
		}

		int index = tagName.lastIndexOf(".");

		if (index <= 0 || index >= (tagName.length() - 1)) {
			return ret;
		}

		String elementName = tagName.substring(index + 1);
		String path = tagName.substring(0, index);

		Element e = _makeElement(path, null);
		if (e != null) {
			for (int i = 0; i < valueList.size(); i++) {
				Object obj = valueList.get(i);
				if (obj != null) {
					Element newElement = new Element(elementName);
					newElement.setText(obj.toString());
					e.addContent(newElement);
				}
			}
			ret = true;
		}

		if (ret) {
			_write();
		}
		return ret;
	}

	/**
	 * 설정항목의 속성을 생성한다.
	 *
	 * @param tagName
	 *            생성할 설정항목 이름
	 * @param attrName
	 *            생성할 속성 이름
	 * @param value
	 *            입력할 문자열값
	 * @return 설정항목 생성에 성공하면 true, 실패하면 false
	 */
	private boolean _make(String tagName, String attrName, String value) {
		boolean ret = false;

		if (!_contains(tagName, attrName)) {
			Attribute attr = _makeAttribute(tagName, attrName, value);
			if (attr != null) {
				ret = true;
			}
			if (ret) {
				_write();
			}
		}

		return ret;
	}

	/**
	 * 설정항목의 속성을 생성한다.
	 *
	 * @param tagName
	 *            생성할 설정항목 이름
	 * @param attrName
	 *            생성할 속성 이름
	 * @param value
	 *            입력할 int값
	 * @return 설정항목 생성에 성공하면 true, 실패하면 false
	 */
	private boolean _make(String tagName, String attrName, int value) {
		return _make(tagName, attrName, "" + value);
	}

	/**
	 * 설정항목의 값(문자열)을 리턴한다.
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @return 설정항목 값. 항목이 존재하지 않을 경우 null 리턴
	 */
	private String _getString(String tagName) {
		String ret = null;

		Element e = _getElement(tagName, null);
		if (e != null) {
			ret = e.getText();
		}
		return ret;
	}

	/**
	 * 설정항목의 값(int)을 리턴한다.
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @return 설정항목 값. 항목이 존재하지 않거나 int 값이 아닐 경우 -1 리턴
	 */
	private int _getInt(String tagName) {
		int ret = -1;

		Element e = _getElement(tagName, null);
		if (e != null) {
			String value = e.getText();

			try {
				ret = Integer.parseInt(value);
			} catch (NumberFormatException nfe) {
			}
		}

		return ret;
	}

	/**
	 * 설정항목의 값(long)을 리턴한다.
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @return 설정항목 값. 항목이 존재하지 않거나 long 값이 아닐 경우 -1 리턴
	 */
	private long _getLong(String tagName) {
		long ret = -1L;

		Element e = _getElement(tagName, null);
		if (e != null) {
			String value = e.getText();

			try {
				ret = Long.parseLong(value);
			} catch (NumberFormatException nfe) {
			}
		}

		return ret;
	}

	/**
	 * 설정항목의 값 리스트을 리턴한다.
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @return 설정항목 리스트. 항목이 존재하지 않을 경우 크기가 0인 리스트 리턴
	 */
	private List _getList(String tagName) {
		Vector ret = new Vector();

		_read();

		if (tagName == null) {
			return ret;
		}

		int index = tagName.lastIndexOf(".");

		if (index <= 0 || index >= (tagName.length() - 1)) {
			return ret;
		}

		String elementName = tagName.substring(index + 1);
		String path = tagName.substring(0, index);

		Element e = _getElement(path, null);
		if (e != null) {
			List l = e.getChildren();

			for (int i = 0; i < l.size(); i++) {
				Element tmpElement = (Element) l.get(i);
				if (tmpElement.getName().equalsIgnoreCase(elementName)) {
					String text = tmpElement.getText().trim();
					if (!text.equals("")) {
						ret.add(text);
					}
				}
			}
		}

		return ret;
	}
	
	private List _getChildList(String tagName) {
		Vector ret = new Vector();

		_read();

		if (tagName == null) {
			return ret;
		}

		Element e = _getElement(tagName, null);
		if (e != null) {
			return e.getChildren();
		}

		return ret;
	}

	/**
	 * 설정항목의 속성값(문자열)을 리턴한다.
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @param attrName
	 *            속성 이름
	 * @return 설정항목의 속성값. 항목이나 속성이 존재하지 않을 경우 null 리턴
	 */
	private String _getString(String tagName, String attrName) {
		String ret = null;

		Attribute attr = _getAttribute(tagName, attrName);
		if (attr != null) {
			ret = attr.getValue();
		}

		return ret;
	}

	/**
	 * 설정항목의 속성값(int)을 리턴한다.
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @param attrName
	 *            속성 이름
	 * @return 설정항목의 속성값. 항목이나 속성이 존재하지 않을 경우 -1 리턴
	 */
	private int _getInt(String tagName, String attrName) {
		int ret = -1;

		Attribute attr = _getAttribute(tagName, attrName);
		if (attr != null) {
			try {
				ret = attr.getIntValue();
			} catch (DataConversionException dce) {
			}
		}

		return ret;
	}

	/**
	 * 설정항목의 값(문자열)을 수정한다. 원본 값과 비교한 후, 같을 경우만 수정한다.
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @param oldValue
	 *            원본 값
	 * @param newValue
	 *            수정 값
	 * @return 수정에 성공하면 true, 실패하면 false
	 */
	private synchronized boolean _set(String tagName, String oldValue,
			String newValue) {
		boolean ret = false;

		Element e = _getElement(tagName, null);
		if (e != null) {
			if (e.getText().equals(oldValue)) {
				e.setText(newValue);
				ret = true;
			}
		}

		if (ret) {
			_write();
		}
		return ret;
	}

	/**
	 * 설정항목의 값(int)을 수정한다. 원본 값과 비교한 후, 같을 경우만 수정한다.
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @param oldValue
	 *            원본 값
	 * @param newValue
	 *            수정 값
	 * @return 수정에 성공하면 true, 실패하면 false
	 */
	private synchronized boolean _set(String tagName, int oldValue, int newValue) {
		boolean ret = false;

		Element e = _getElement(tagName, null);
		if (e != null) {
			int value = -1;
			try {
				value = Integer.parseInt(e.getText());
			} catch (NumberFormatException nfe) {
			}

			if (value == oldValue) {
				e.setText("" + newValue);
				ret = true;
			}
		}
		if (ret) {
			_write();
		}
		return ret;
	}

	/**
	 * 설정항목의 리스트을 수정한다.(사용안함) 원본 리스트과 비교한 후, 같을 경우만 수정한다.
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @param oldList
	 *            원본 리스트
	 * @param newList
	 *            수정 리스트
	 * @return 수정에 성공하면 true, 실패하면 false
	 */
	private synchronized boolean _set(String tagName, List oldList, List newList) {
		boolean ret = false;

		if (ret) {
			_write();
		}
		return ret;
	}

	/**
	 * 설정항목의 속성 값(문자열)을 수정한다. 원본 값과 비교한 후, 같을 경우만 수정한다.
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @param attrName
	 *            속성 이름
	 * @param oldValue
	 *            원본 값
	 * @param newValue
	 *            수정 값
	 * @return 수정에 성공하면 true, 실패하면 false
	 */
	private synchronized boolean _set(String tagName, String attrName,
			String oldValue, String newValue) {
		boolean ret = false;

		Attribute attr = _getAttribute(tagName, attrName);
		if (attr != null) {
			if (attr.getValue().equals(oldValue)) {
				attr.setValue(newValue);
				ret = true;
			}
		}

		if (ret) {
			_write();
		}
		return ret;
	}

	/**
	 * 설정항목의 속성 값(int)을 수정한다. 원본 값과 비교한 후, 같을 경우만 수정한다.
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @param attrName
	 *            속성 이름
	 * @param oldValue
	 *            원본 값
	 * @param newValue
	 *            수정 값
	 * @return 수정에 성공하면 true, 실패하면 false
	 */
	private synchronized boolean _set(String tagName, String attrName,
			int oldValue, int newValue) {
		boolean ret = false;

		Attribute attr = _getAttribute(tagName, attrName);
		if (attr != null) {
			int value = -1;
			try {
				value = attr.getIntValue();
			} catch (DataConversionException dce) {
			}

			if (value == oldValue) {
				attr.setValue("" + newValue);
				ret = true;
			}
		}

		if (ret) {
			_write();
		}
		return ret;
	}

	/**
	 * 설정파일을 읽어 메모리에 저장한다.
	 */
	private synchronized void _read() {
		try {
			File configFile = new File(xmlURL.getPath());
			if (configFile != null && lastModified != configFile.lastModified()) {
				URLConnection urlConn = xmlURL.openConnection();
				InputStream is = urlConn.getInputStream();
				try {
					Document tempXMLDoc = sax.build(is);
					if (tempXMLDoc != null) {
						xmlDoc = tempXMLDoc;
					}
				} catch (JDOMException jdome) {
					if (Constants.DEBUG_MODE) {
						System.out.println("'" + configFile + "' 파일을 분석하는 중에 에러가 발생하였습니다.");
						// 파일을 초기화한다.
						//initConfig();
					}
					is.close();
				}
				is.close();
				lastModified = configFile.lastModified();
			//	_versionCheck();
			}
		} catch (IOException ioe) {
			if (Constants.DEBUG_MODE) {
				System.out.println("'" + configFile + "' 파일을 읽는 중 에러가 발생하였습니다.");
			}

			if (xmlDoc == null) {
				System.exit(0);
			}
		}
	}

	/**
	 * 메모리 내용을 설정파일에 저장한다.
	 */
	private synchronized void _write() {
		try {
			OutputStream os = new FileOutputStream(xmlURL.getFile());
			xmlOut.output(xmlDoc, os);
			os.close();
		} catch (IOException ioe) {
			if (Constants.DEBUG_MODE) {
				System.out.println("'" + configFile + "' 파일을 쓰는 중 에러가 발생하였습니다.\n" + ioe);
			}
			System.exit(0);
		}
	}

	/**
	 *
	 */
	private void _versionCheck() {
		String version = _getString(DEFAULT_PATH, VERSION_NAME);

		if (version != null && version.equals(VERSION)) {
		} else {
			if (Constants.DEBUG_MODE) {
				System.out.println("\"" + xmlURL.getFile() + "\" 파일의 버전이 틀립니다.");
				System.out.println("필요 버전 = " + VERSION);
				System.out.println("현재 버전 = " + version);
			}
			System.exit(0);
		}
	}

	/**
	 * 설정파일을 초기화한다.
	 *
	 */
	private void _initConfig() {
		if (Constants.DEBUG_MODE) {
			System.out.println("'" + configFile + "' 파일을 새로 초기화합니다.");
		}

		if (xmlDoc == null) {
			xmlDoc = new Document();
			xmlDoc.addContent(new Comment("eClix 설정파일입니다."));
			_make(DEFAULT_PATH, VERSION_NAME, VERSION);
			_write();
		}
	}

	/**
	 * 엘레멘트를 리턴한다.
	 */
	private Element _getElement(String tagName, Element e) {
		Element ret = null;

		if (tagName == null) {
			return e;
		}

		_read();

		int length = tagName.length();
		int index = tagName.indexOf(".");
		index = (index > 0) ? index : length;

		String elementName = tagName.substring(0, index);

		Element child = null;

		if (e == null) {
			if (xmlDoc.hasRootElement()) {
				if (xmlDoc.getRootElement().getName().equalsIgnoreCase(
						elementName)) {
					child = xmlDoc.getRootElement();
					ret = _getElement((index < length) ? tagName.substring(
							index + 1, length) : null, child);
				}
			} else {
				return ret;
			}
		} else {
			List list = e.getChildren();
			
			for (int i = 0; i < list.size(); i++) {
				child = (Element) list.get(i);
				if (child.getName().equalsIgnoreCase(elementName)) {
					ret = _getElement((index < length) ? tagName.substring(
							index + 1, length) : null, child);
					if (ret != null) {
						break;
					}
				}
			}
		}

		return ret;
	}

	/**
	 * 어트리뷰트를 리턴한다.
	 */
	private Attribute _getAttribute(String tagName, String attrName) {
		Attribute ret = null;

		Element e = _getElement(tagName, null);
		if (e != null) {
			Attribute attr = null;

			List list = e.getAttributes();
			boolean flag = true;
			for (int i = 0; i < list.size(); i++) {
				attr = (Attribute) list.get(i);
				if (attr.getName().equalsIgnoreCase(attrName)) {
					ret = attr;
					break;
				}
			}
		}

		return ret;
	}

	/**
	 * 엘레멘트를 추가한다.
	 */
	private Element _makeElement(String tagName, Element e) {
		Element ret = null;

		if (tagName == null) {
			return e;
		}

		int length = tagName.length();
		int index = tagName.indexOf(".");
		index = (index > 0) ? index : length;

		String elementName = tagName.substring(0, index);
		Element child = null;

		if (e == null) {
			if (xmlDoc.hasRootElement()) {
				child = xmlDoc.getRootElement();
				if (child.getName().equalsIgnoreCase(elementName)) {
				} else {
					return ret;
				}
			} else {
				Element newElement = new Element(elementName);
				xmlDoc.setRootElement(newElement);
				child = newElement;
			}
		} else {
			List list = e.getChildren();

			boolean flag = true;
			for (int i = 0; i < list.size(); i++) {
				child = (Element) list.get(i);
				if (child.getName().equalsIgnoreCase(elementName)) {
					flag = false;
					break;
				}
			}

			if (flag) {
				Element newElement = new Element(elementName);
				e.addContent(newElement);
				child = newElement;
			}

		}

		ret = _makeElement((index < length) ? tagName.substring(index + 1,
				length) : null, child);

		return ret;
	}

	private Attribute _makeAttribute(String tagName, String attrName,
			String value) {
		Attribute ret = null;

		Element e = _makeElement(tagName, null);
		if (e != null) {
			Attribute attr = null;

			List list = e.getAttributes();
			boolean flag = true;
			for (int i = 0; i < list.size(); i++) {
				attr = (Attribute) list.get(i);
				if (attr.getName().equalsIgnoreCase(attrName)) {
					attr.setValue(value);
					flag = false;
					break;
				}
			}
			if (flag) {
				attr = new Attribute(attrName, value);
				e.setAttribute(attr);
			}
			ret = attr;
		}
		return ret;
	}

	////////////////////////////////////////////////
	/**
	 * 설정항목이 존재하는지 검사
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @return 존재할 경우 true, 존재하지 않을 경우 false
	 *
	 */
	public static boolean contains(String tagName) {
		return getInstance()._contains(tagName);
	}

	/**
	 * 설정항목의 속성이 존재하는지 검사
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @param attrName
	 *            속성 이름
	 * @return 존재할 경우 true, 존재하지 않을 경우 false
	 *
	 */
	public static boolean contains(String tagName, String attrName) {
		return getInstance()._contains(tagName, attrName);
	}

	/**
	 * 설정항목을 생성한다.
	 *
	 * @param tagName
	 *            생성할 설정항목 이름
	 * @param value
	 *            입력할 문자열값
	 * @return 설정항목 생성에 성공하면 true, 실패하면 false
	 */
	public static boolean make(String tagName, String value) {
		return getInstance()._make(tagName, value);
	}

	/**
	 * 설정항목을 생성한다.
	 *
	 * @param tagName
	 *            생성할 설정항목 이름
	 * @param value
	 *            입력할 int값
	 * @return 설정항목 생성에 성공하면 true, 실패하면 false
	 */
	public static boolean make(String tagName, int value) {
		return getInstance()._make(tagName, "" + value);
	}

	/**
	 * 설정항목을 생성한다.
	 *
	 * 리스트에 들어 있는 내용은 모두 String으로 처리한다.
	 *
	 * @param tagName
	 *            생성할 설정항목 이름
	 * @param value
	 *            입력할 리스트
	 * @return 설정항목 생성에 성공하면 true, 실패하면 false
	 */
	public static boolean make(String tagName, List valueList) {
		return getInstance()._make(tagName, valueList);
	}

	/**
	 * 설정항목의 속성을 생성한다.
	 *
	 * @param tagName
	 *            생성할 설정항목 이름
	 * @param attrName
	 *            생성할 속성 이름
	 * @param value
	 *            입력할 문자열값
	 * @return 설정항목 생성에 성공하면 true, 실패하면 false
	 */
	public static boolean make(String tagName, String attrName, String value) {
		return getInstance()._make(tagName, attrName, value);
	}

	/**
	 * 설정항목의 속성을 생성한다.
	 *
	 * @param tagName
	 *            생성할 설정항목 이름
	 * @param attrName
	 *            생성할 속성 이름
	 * @param value
	 *            입력할 int값
	 * @return 설정항목 생성에 성공하면 true, 실패하면 false
	 */
	public static boolean make(String tagName, String attrName, int value) {
		return getInstance()._make(tagName, attrName, "" + value);
	}

	/**
	 * 설정항목의 값(문자열)을 리턴한다.
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @return 설정항목 값. 항목이 존재하지 않을 경우 null 리턴
	 */
	public static String getString(String tagName) {
		return getInstance()._getString(tagName);
	}

	/**
	 * 설정항목의 값(int)을 리턴한다.
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @return 설정항목 값. 항목이 존재하지 않거나 int 값이 아닐 경우 -1 리턴
	 */
	public static int getInt(String tagName) {
		return getInstance()._getInt(tagName);
	}

	/**
	 * 설정항목의 값(long)을 리턴한다.
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @return 설정항목 값. 항목이 존재하지 않거나 long 값이 아닐 경우 -1 리턴
	 */
	public static long getLong(String tagName) {
		return getInstance()._getLong(tagName);
	}

	/**
	 * 설정항목의 값 리스트을 리턴한다.
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @return 설정항목 리스트. 항목이 존재하지 않을 경우 크기가 0인 리스트 리턴
	 */
	public static List getList(String tagName) {
		return getInstance()._getList(tagName);
	}
	public static List getChildList(String tagName) {
		return getInstance()._getChildList(tagName);
	}

	/**
	 * 설정항목의 속성값(문자열)을 리턴한다.
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @param attrName
	 *            속성 이름
	 * @return 설정항목의 속성값. 항목이나 속성이 존재하지 않을 경우 null 리턴
	 */
	public static String getString(String tagName, String attrName) {
		return getInstance()._getString(tagName, attrName);
	}

	/**
	 * 설정항목의 속성값(int)을 리턴한다.
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @param attrName
	 *            속성 이름
	 * @return 설정항목의 속성값. 항목이나 속성이 존재하지 않을 경우 -1 리턴
	 */
	public static int getInt(String tagName, String attrName) {
		return getInstance()._getInt(tagName, attrName);
	}

	/**
	 * 설정항목의 값(문자열)을 수정한다. 원본 값과 비교한 후, 같을 경우만 수정한다.
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @param oldValue
	 *            원본 값
	 * @param newValue
	 *            수정 값
	 * @return 수정에 성공하면 true, 실패하면 false
	 */
	public static synchronized boolean set(String tagName, String oldValue,
			String newValue) {
		return getInstance()._set(tagName, oldValue, newValue);
	}

	/**
	 * 설정항목의 값(int)을 수정한다. 원본 값과 비교한 후, 같을 경우만 수정한다.
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @param oldValue
	 *            원본 값
	 * @param newValue
	 *            수정 값
	 * @return 수정에 성공하면 true, 실패하면 false
	 */
	public static synchronized boolean set(String tagName, int oldValue,
			int newValue) {
		return getInstance()._set(tagName, oldValue, newValue);
	}

	/**
	 * 설정항목의 리스트을 수정한다.(사용안함) 원본 리스트과 비교한 후, 같을 경우만 수정한다.
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @param oldList
	 *            원본 리스트
	 * @param newList
	 *            수정 리스트
	 * @return 수정에 성공하면 true, 실패하면 false
	 */
	public static synchronized boolean set(String tagName, List oldList,
			List newList) {
		return getInstance()._set(tagName, oldList, newList);
	}

	/**
	 * 설정항목의 속성 값(문자열)을 수정한다. 원본 값과 비교한 후, 같을 경우만 수정한다.
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @param attrName
	 *            속성 이름
	 * @param oldValue
	 *            원본 값
	 * @param newValue
	 *            수정 값
	 * @return 수정에 성공하면 true, 실패하면 false
	 */
	public static synchronized boolean set(String tagName, String attrName,
			String oldValue, String newValue) {
		return getInstance()._set(tagName, attrName, oldValue, newValue);
	}

	/**
	 * 설정항목의 속성 값(int)을 수정한다. 원본 값과 비교한 후, 같을 경우만 수정한다.
	 *
	 * @param tagName
	 *            설정항목 이름
	 * @param attrName
	 *            속성 이름
	 * @param oldValue
	 *            원본 값
	 * @param newValue
	 *            수정 값
	 * @return 수정에 성공하면 true, 실패하면 false
	 */
	public static synchronized boolean set(String tagName, String attrName,
			int oldValue, int newValue) {
		return getInstance()._set(tagName, attrName, oldValue, newValue);
	}

	/**
	 * 설정파일을 읽어 메모리에 저장한다.
	 */
	public static synchronized void read() {
		getInstance()._read();
	}

	/**
	 * 메모리 내용을 설정파일에 저장한다.
	 */
	public static synchronized void write() {
		getInstance()._write();
	}
}
